﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.IO;
using System.Windows.Controls;
using System.Windows.Data;
using System.Collections;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.WindowsAPICodePack.Shell;
using Microsoft.WindowsAPICodePack.Dialogs;
using System.Windows.Threading;
using HalconDotNet;
using System.Runtime.InteropServices;

namespace Project1
{
    public delegate void DisplayResultsDelegate();
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        private ContextMenu cm;
        private HTuple hv_ModelID = null;
        private HObject modelImage = null;
        private List<HTuple> drawing_objects;
        private List<Point> points;
        private List<Circle> circles;
        private List<Line> lines;
        private List<Plan> plans;
        HDrawingObject.HDrawingObjectCallback cb;
        HObject ho_EdgeAmplitude, ho_ImageReduced;
        object image_lock = new object();
        HTuple hv_Number = null, hv_RefRow = null;
        List<HObject> saved_ROI_Contours;
        HObject ho_ModelContours = null;

        // Local control variables 

        //AmplitudeThreshold := 40
        //RoiWidthLen2 := 5
       
        HTuple hv_Width = new HTuple(), hv_Height = new HTuple();
        
        private HObject ho_Image = new HObject();     //图像变量

        //HDClip hdc = new HDClip();
        DispatcherTimer Timer;
        public MainWindow()
        {
            InitializeComponent();
            drawing_objects = new List<HTuple>();
            saved_ROI_Contours = new List<HObject>();
            points = new List<Point>();
            circles = new List<Circle>();
            lines = new List<Line>();
            plans = new List<Plan>();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            //HOperatorSet.AttachBackgroundToWindow(ho_Image, hSmartWindowControlWPF1.HalconWindow);
        }



        private void hWindowControlWPF1_HInitWindow(object sender, EventArgs e)
        {
            // Initialize window
            // - Read and attach background image
            // - Initialize display results delegate function
            // - Initialize callbacks
            Utils.hv_ExpDefaultWinHandle = hSmartWindowControlWPF1.HalconWindow;
            ho_Image.GenEmptyObj();
            HOperatorSet.ReadImage(out ho_Image, "D:/Documents/Desktop/Sample.bmp");
            HOperatorSet.GetImageSize(ho_Image, out hv_Width, out hv_Height);
            hSmartWindowControlWPF1.HalconWindow.SetPart(0.0, 0.0, hv_Height - 1, hv_Width - 1);
            hSmartWindowControlWPF1.HalconWindow.AttachBackgroundToWindow(new HImage(ho_Image));

            /*display_results_delegate = new DisplayResultsDelegate(() =>
            {
                lock (image_lock)
                {
                    if (ho_EdgeAmplitude != null)
                        Utils.display_results(ho_EdgeAmplitude);
                }
            });*/
            //cb = new HDrawingObject.HDrawingObjectCallback(DisplayCallback);
        }

        private void SetCallbacks(HTuple draw_id)
        {
            drawing_objects.Add(draw_id);
            /* // Set callbacks for all relevant interactions
             IntPtr ptr = Marshal.GetFunctionPointerForDelegate(cb);
             HOperatorSet.SetDrawingObjectCallback(draw_id, "on_resize", ptr);
             HOperatorSet.SetDrawingObjectCallback(draw_id, "on_drag", ptr);
             HOperatorSet.SetDrawingObjectCallback(draw_id, "on_attach", ptr);
             HOperatorSet.SetDrawingObjectCallback(draw_id, "on_select", ptr);
             lock (image_lock)
             {
                 HOperatorSet.AttachDrawingObjectToWindow(hSmartWindowControlWPF1.HalconID, draw_id);
             }*/
        }

        private void Button_OpenFile (object sender, RoutedEventArgs e)
        {

            var fileName = Utils.get_path(false);
            if (fileName != "")
            {
                HOperatorSet.GenEmptyObj(out ho_Image);
                ho_Image.Dispose();
                HOperatorSet.ReadImage(out ho_Image, fileName);
                HOperatorSet.Rgb1ToGray(ho_Image, out ho_Image);
                
                HOperatorSet.DispObj(ho_Image, hSmartWindowControlWPF1.HalconWindow);
                HOperatorSet.GetImageSize(ho_Image, out hv_Width, out hv_Height);
                HOperatorSet.SetPart(hSmartWindowControlWPF1.HalconWindow, 0, 0, hv_Height-1, hv_Width-1);
                HOperatorSet.ClearWindow(hSmartWindowControlWPF1.HalconWindow);
                //HOperatorSet.AttachBackgroundToWindow(new HImage(ho_Image),hSmartWindowControlWPF1.HalconID);
               // HOperatorSet.AttachBackgroundToWindow(ho_Image, hSmartWindowControlWPF1.HalconWindow);

            }

        }

        private void OnRectangle1_Click(object sender, RoutedEventArgs e)
        {
            // Execute context menu command:
            // Add new rectangle1 drawing object
            HTuple draw_id;
            Utils.add_new_drawing_object("rectangle1", hSmartWindowControlWPF1.HalconID, out draw_id);
            SetCallbacks(draw_id);

        }

        private void Button_Click_ZoomDown(object sender, RoutedEventArgs e)
        {
            //Utils.ImageZoom(ho_Image,windowHandle, 0.5, true);
        }

        private void Button_Click_ZoomUp(object sender, RoutedEventArgs e)
        {
            // hdc.RunHalcon(hwMainWindow.HalconWindow);
            //hwMainWindow.SetFullImagePart(null);//使图片全屏显示在屏幕上
            // hwMainWindow.HalconWindow.SetPart(0, 0, -2, -2);  //使图片自适应屏幕
            Utils.ImageZoom(ho_Image, 1.5, true);

        }

        private void Button_Click_Adapt(object sender, RoutedEventArgs e)
        {
  
            HOperatorSet.SetPart(hSmartWindowControlWPF1.HalconWindow, 0.0, 0.0, hv_Height - 1, hv_Width - 1);
            HOperatorSet.ClearWindow(hSmartWindowControlWPF1.HalconWindow);
            HOperatorSet.DispObj(ho_Image, hSmartWindowControlWPF1.HalconWindow);
        }

        private void Button_Detect_Point(object sender, RoutedEventArgs e)
        {
            //HOperatorSet.ClearWindow(Utils.hv_ExpDefaultWinHandle);
            this.hSmartWindowControlWPF1.ContextMenu = null;
            HTuple rowStart , rowEnd , colStart, colEnd, Nr, Nc, Dist;
            HTuple mode = new HTuple("positive");
            HObject ROI = Utils.get_ROI_from_drawingObject(drawing_objects);
            if (ROI == null)
            {
                MessageBox.Show("未能检测到ROI区域", "提示", MessageBoxButton.OK);
                return;
            }
            //Line line = Utils.get_line_fromROI(ho_Image, ROI, Threshold1, Threshold2);
            HOperatorSet.DispObj(ROI, Utils.hv_ExpDefaultWinHandle);
            HOperatorSet.FitLineContourXld(ROI, "regression", -1, 0, 5, 1.5, out rowEnd, out colEnd, out rowStart, out colStart, out Nr, out Nc, out Dist);
            Point point = Utils.get_point_fromLine(ho_Image,mode , rowStart, colStart, rowEnd, colEnd);
            if (point == null)
            {
                MessageBox.Show("未能检测到点", "提示", MessageBoxButton.OK);
            }
            else
            {
                //线段属于轮廓
                //HObject contours = null;
                //HOperatorSet.GenContourRegionXld(ROI, out contours,new HTuple("border"));
                Plan plan = new Plan(Plan.MEASURE_POINT,mode,ROI);
                plans.Add(plan);
                saved_ROI_Contours.Add(new HObject(ROI)); 
                points.Add(point);
            }

            //HOperatorSet.DrawLine(Utils.hv_ExpDefaultWinHandle, out rowStart, out colStart, out rowEnd, out colEnd);   hsamrt窗口不支持画图

            /*    
            */
            RemoveDrawingObject();
            this.hSmartWindowControlWPF1.ContextMenu = cm;
        }

        private void Button_Detect_Line(object sender, RoutedEventArgs e)
        {
            HOperatorSet.ClearWindow(Utils.hv_ExpDefaultWinHandle);
            this.hSmartWindowControlWPF1.ContextMenu = null;
            //输入的灰度阈值范围先设置成0到20
            HTuple Threshold1 = new HTuple(0), Threshold2 = new HTuple(20);
            HObject ROI = Utils.get_ROI_from_drawingObject(drawing_objects);
            if(ROI == null)
            {
                MessageBox.Show("未能检测到ROI区域", "提示", MessageBoxButton.OK);
                return;
            }
            Line line = Utils.get_line_fromROI(ho_Image, ROI, Threshold1, Threshold2);
            if(line == null)
            {
                MessageBox.Show("未能检测到线", "提示", MessageBoxButton.OK);
            }
            else
            {
                HObject contours = null;
                HOperatorSet.GenContourRegionXld(ROI, out contours, new HTuple("border"));
                saved_ROI_Contours.Add(new HObject(contours));
                Plan plan = new Plan(Plan.MEASURE_LINE, Threshold1, Threshold2, contours);
                plans.Add(plan);
                lines.Add(line);
            }
            RemoveDrawingObject();
            this.hSmartWindowControlWPF1.ContextMenu = cm;
        }

        private void Button_Detect_Circle(object sender, RoutedEventArgs e)
        {

            HOperatorSet.ClearWindow(Utils.hv_ExpDefaultWinHandle);
            this.hSmartWindowControlWPF1.ContextMenu = null;
            HObject ROI = Utils.get_ROI_from_drawingObject(drawing_objects);
            if (ROI == null)
            {
                MessageBox.Show("未能检测到ROI区域", "提示", MessageBoxButton.OK);
                return;
            }
            HTuple hv_MinRadius = new HTuple(18),hv_MaxRadius = new HTuple(38),hv_Threshold1= new HTuple(40),hv_Threshold2 = new HTuple(255);
            Circle rsCircle = Utils.get_circle_fromROI(ho_Image, ROI, hv_MinRadius, hv_MaxRadius, hv_Threshold1, hv_Threshold2);
            if(rsCircle == null)
            {
                MessageBox.Show("未能检测到圆", "提示", MessageBoxButton.OK);

            }
            else
            {
                HObject contours = null;
                HOperatorSet.GenContourRegionXld(ROI, out contours, new HTuple("border"));
                saved_ROI_Contours.Add(contours);
                Plan plan = new Plan(Plan.MEASURE_CIRCLE, hv_MinRadius, hv_MaxRadius, hv_Threshold1, hv_Threshold2, contours);
                plans.Add(plan);
                circles.Add(rsCircle);
            }
            RemoveDrawingObject();
            this.hSmartWindowControlWPF1.ContextMenu = cm;

        }
        private void Button_DISP_ROI(object sender, RoutedEventArgs e)
        {
            ClearAllObjects();
            HOperatorSet.ClearWindow(Utils.hv_ExpDefaultWinHandle);
           if(saved_ROI_Contours.Count == 0)
            {
                MessageBox.Show("未能检测到ROI区域", "提示", MessageBoxButton.OK);
                return;
            }
            else
            {
                foreach (var ROI in saved_ROI_Contours)
                {
                    HObject region = null;
                    HOperatorSet.GenRegionContourXld(ROI, out region, new HTuple("filled"));
                    HOperatorSet.DispObj(region, Utils.hv_ExpDefaultWinHandle);
                }
                
            }
        }

        
        private void OnClearAllObjects_Click(object sender, RoutedEventArgs e)
        {
            RemoveDrawingObject();
        }
        private void RemoveDrawingObject()
        {
            foreach (var drawing_ID in drawing_objects)
            {
                HOperatorSet.ClearDrawingObject(drawing_ID);
                drawing_objects.Remove(drawing_ID);
                if (drawing_objects.Count == 0) break;
            }

        }
        private void OnExtract_Click(object sender, RoutedEventArgs e)
        {
            HObject ho_Object, ho_ModelContours;
            HObject ROI = null;
            HOperatorSet.GenEmptyObj(out ho_ModelContours);
            HOperatorSet.GenEmptyObj(out ho_Object);
            int len = drawing_objects.Count;
            if (len == 0)
            {
                MessageBox.Show("未能检测到ROI区域", "提示", MessageBoxButton.OK);
                return;
            }
            else
            {
                foreach (var drawing_ID in drawing_objects)
                {
                    HOperatorSet.GetDrawingObjectIconic(out ho_Object, drawing_ID);
                    if(ROI == null)
                    {
                        ROI = ho_Object;
                    }
                    else
                    {
                        HOperatorSet.Union2(ROI, ho_Object, out ROI);
                    }
                }
            }
            
            //ho_ImageReduced.Dispose();
            HOperatorSet.ReduceDomain(ho_Image, ROI, out ho_ImageReduced);
            HOperatorSet.CreateShapeModel(ho_ImageReduced, 5, (new HTuple(0)).TupleRad(),
            (new HTuple(360)).TupleRad(), (new HTuple(0.6174)).TupleRad(),
            (new HTuple("none")).TupleConcat("no_pregeneration"), "use_polarity",
            ((new HTuple(49)).TupleConcat(56)).TupleConcat(22), 10, out hv_ModelID);


            if (hv_ModelID != null)
            {
               
                Utils.get_modelImage(ho_Image, out modelImage, hv_ModelID);
                HOperatorSet.DispObj(modelImage,Utils.hv_ExpDefaultWinHandle);
                MessageBox.Show("成功提取模型", "结果", MessageBoxButton.OK);
                HOperatorSet.AttachBackgroundToWindow(modelImage, hSmartWindowControlWPF1.HalconWindow);
                
                ho_Image = modelImage;
                
            }
            else
            {
                MessageBox.Show("提取失败", "结果", MessageBoxButton.OK);
            }

            RemoveDrawingObject();
        }

        private void OnRegister_Click(object sender, RoutedEventArgs e)
        {
            if(hv_ModelID == null)
            {
                MessageBox.Show("不存在已经提取的模板", "错误",MessageBoxButton.OK);
                return;
            }
            Utils.save_model(hv_ModelID,ho_Image,modelImage);
        }

        private void hSmartWindowControlWPF1_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
        {
            cm = this.FindResource("cmButton") as ContextMenu;
            cm.PlacementTarget = sender as Button;
            cm.IsOpen = true;
        }

        private void OnRectangle2_Click(object sender, RoutedEventArgs e)
        {
            // Execute context menu command:
            // Add new rectangle2 drawing object
            HTuple draw_id;
            Utils.add_new_drawing_object("rectangle2", hSmartWindowControlWPF1.HalconID, out draw_id);
            SetCallbacks(draw_id);
        }

        private void Button_Load_ShapeModel(object sender, RoutedEventArgs e)
        {
            HTuple hv_Score,hv_Column,hv_Angle,hv_Area;
            HTuple hv_RefColumn = new HTuple(), hv_HomMat2D = new HTuple(), hv_Row = new HTuple();
            HObject ho_TransContours;
            if (hv_ModelID != null)
            {
                var result = MessageBox.Show("已经打开了一个模板,要重新选择吗", "提示", MessageBoxButton.YesNo);
                if (result == MessageBoxResult.No)
                {
                    return;
                }
            }
            var fileName = Utils.get_path(false);
        
            if (fileName != "")
            {
                    string[] sArray = fileName.Split('.');
                    string prefix = sArray.AsQueryable().Last();
                    string modelImagePath = fileName.Replace(prefix, "bmp");
                    if (!File.Exists(modelImagePath))
                    {
                        MessageBox.Show("未能找到模板图片");
                        return;
                    }
                    
                   HOperatorSet.ReadShapeModel(fileName, out hv_ModelID);
                 
                   HOperatorSet.GenEmptyObj(out ho_Image);
                   HOperatorSet.ReadImage(out ho_Image, modelImagePath);
      
                   HOperatorSet.FindShapeModel(ho_Image, hv_ModelID, (new HTuple(0)).TupleRad(),
                       (new HTuple(360)).TupleRad(), 0.5, 1, 0.5, "least_squares",
                       (new HTuple(6)).TupleConcat(1), 0.75, out hv_Row, out hv_Column, out hv_Angle, out hv_Score);
                   Utils.modelCentreRow = hv_Row.Clone();
                   Utils.modelCentreColumn = hv_Column.Clone();

                HOperatorSet.AttachBackgroundToWindow(ho_Image,Utils.hv_ExpDefaultWinHandle);
                /*
                   HOperatorSet.AttachBackgroundToWindow(ho_Image, Utils.hv_ExpDefaultWinHandle);
                  // HOperatorSet.DispObj(ho_Image, Utils.hv_ExpDefaultWinHandle);
                   for (hv_I = 0; (int)hv_I <= (int)((new HTuple(hv_Score.TupleLength())) - 1); hv_I = (int)hv_I + 1)
                   {
                       ho_TransContours.Dispose();
                       Utils.trans_contours(ho_ModelContours, out ho_TransContours, hv_Angle.TupleSelect(
                       hv_I), hv_Row.TupleSelect(hv_I), hv_Column.TupleSelect(hv_I));
                       HOperatorSet.AreaCenterPointsXld(ho_TransContours, out hv_Area2, out hv_centre_row,  out hv_centre_col);
                       Utils.disp_linelen(hv_centre_row, hv_centre_col, hv_WindowHandle);
                       HOperatorSet.SetColor(Utils.hv_ExpDefaultWinHandle, "yellow");
                       HOperatorSet.GenEmptyObj(out ho_Contour);
                       HOperatorSet.GenContourPolygonXld(out ho_Contour, hv_centre_row, hv_centre_col);

                       HOperatorSet.FitLineContourXld(ho_Contour, "tukey", 20, 0, 10, 2, out hv_RowBegin,
                           out hv_ColBegin, out hv_RowEnd, out hv_ColEnd, out hv_Nr, out hv_Nc, out hv_Dist);

                       Utils.measure_line(ho_Image, hv_RowBegin, hv_ColBegin, hv_RowEnd, hv_ColEnd, hv_AmplitudeThreshold,
                           hv_RoiWidthLen2, hv_WindowHandle, hv_Angle, "extend", "all", out hv_Row_Measure,
                           out hv_Col_Measure, out hv_Amplitude_Measure, out hv_Distance_Measure,
                           out hv_Draw_IDArray);

                       removeDrawingObject();
                   }*/
            }

        }

        private void Model_Matching()
        {
            HTuple homMat2D, hv_Row, hv_Column, hv_Angle, hv_Score;
            if (hv_ModelID == null)
            {
                var result = MessageBox.Show("请先加载模板！", "提示", MessageBoxButton.OK);
                return;
            }
            HOperatorSet.FindShapeModel(ho_Image, hv_ModelID, (new HTuple(0)).TupleRad(),
             (new HTuple(360)).TupleRad(), 0.5, 1, 0.5, "least_squares",
             (new HTuple(6)).TupleConcat(1), 0.75, out hv_Row, out hv_Column, out hv_Angle, out hv_Score);
            HOperatorSet.VectorAngleToRigid(Utils.modelCentreRow, Utils.modelCentreColumn, 0, hv_Row, hv_Column,  hv_Angle, out homMat2D);
            foreach(var plan in plans)
            {
                string planType = plan.getPlanType();

                Object obj = plan.execute(ho_Image, homMat2D);
                MessageBox.Show("下一个");
                if(obj == null)
                {
                    MessageBox.Show("NG", "次品", MessageBoxButton.OK);
                    return;
                }
                if (planType == "circle")
                {
                    circles.Add(new Circle((Circle)obj));
                 }
                else if(planType == "line")
                {
                    lines.Add(new Line((Line)obj));
                }
                else if(planType == "point")
                {
                    points.Add(new Point((Point)obj));
                }
                else
                {
                    MessageBox.Show("异常", "警告", MessageBoxButton.OK);
                    return;
                }
            }
            MessageBox.Show("WellDone", "通知", MessageBoxButton.OK);

        }
        private void OnCircle_Click(object sender, RoutedEventArgs e)
        {
            // Execute context menu command:
            // Add new circle drawing object
            HTuple draw_id;
            Utils.add_new_drawing_object("circle", hSmartWindowControlWPF1.HalconID, out draw_id);
            SetCallbacks(draw_id);
            Console.WriteLine();
        }

        private void OnEllipse_Click(object sender, RoutedEventArgs e)
        {
            // Execute context menu command:
            // Add new ellipse drawing object
            HTuple draw_id;
            Utils.add_new_drawing_object("ellipse", hSmartWindowControlWPF1.HalconID, out draw_id);
            SetCallbacks(draw_id);
        }

        private void OnLine_Click(object sender, RoutedEventArgs e)
        {
            // Execute context menu command:
            // Add new ellipse drawing object
            HTuple draw_id;
            Utils.add_new_drawing_object("line", hSmartWindowControlWPF1.HalconID, out draw_id);
            SetCallbacks(draw_id);
        }

        private void Button_MATCHING(object sender,RoutedEventArgs e)
        {
            Model_Matching();
        }
        private void ClearAllObjects()
        {
            lock (image_lock)
            {
                foreach (HTuple dobj in drawing_objects)
                {
                    HOperatorSet.ClearDrawingObject(dobj);
                }
                drawing_objects.Clear();
            }
            hSmartWindowControlWPF1.HalconWindow.ClearWindow();
        }
     }
}
